<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
<!-- hellovulkanwindow.qdoc -->
  <title>Hello Vulkan Window Example | Qt GUI 5.14.2</title>
  <link rel="stylesheet" type="text/css" href="style/offline-simple.css" />
  <script type="text/javascript">
    document.getElementsByTagName("link").item(0).setAttribute("href", "style/offline.css");
    // loading style sheet breaks anchors that were jumped to before
    // so force jumping to anchor again
    setTimeout(function() {
        var anchor = location.hash;
        // need to jump to different anchor first (e.g. none)
        location.hash = "#";
        setTimeout(function() {
            location.hash = anchor;
        }, 0);
    }, 0);
  </script>
</head>
<body>
<div class="header" id="qtdocheader">
  <div class="main">
    <div class="main-rounded">
      <div class="navigationbar">
        <table><tr>
<td ><a href="../qtdoc/index.html">Qt 5.14</a></td><td ><a href="qtgui-index.html">Qt GUI</a></td><td >Hello Vulkan Window Example</td></tr></table><table class="buildversion"><tr>
<td id="buildversion" width="100%" align="right"><a href="qtgui-index.html">Qt 5.14.2 Reference Documentation</a></td>
        </tr></table>
      </div>
    </div>
<div class="content">
<div class="line">
<div class="content mainContent">
<div class="sidebar">
<div class="toc">
<h3><a name="toc">Contents</a></h3>
<ul>
<li class="level1"><a href="#startup">Startup</a></li>
<li class="level1"><a href="#the-qvulkanwindow-subclass">The QVulkanWindow Subclass</a></li>
<li class="level1"><a href="#the-actual-rendering">The Actual Rendering</a></li>
<li class="level1"><a href="#running-the-example">Running the Example</a></li>
</ul>
</div>
<div class="sidebar-content" id="sidebar-content"></div></div>
<h1 class="title">Hello Vulkan Window Example</h1>
<span class="subtitle"></span>
<!-- $$$hellovulkanwindow-brief -->
<p>Shows the basics of using <a href="qvulkanwindow.html">QVulkanWindow</a>.</p>
<!-- @@@hellovulkanwindow -->
<!-- $$$hellovulkanwindow-description -->
<div class="descr"> <a name="details"></a>
<p>The <i>Hello Vulkan Window Example</i> shows the basics of using <a href="qvulkanwindow.html">QVulkanWindow</a> in order to display rendering with the Vulkan graphics API on systems that support this.</p>
<p class="centerAlign"><img src="images/hellovulkanwindow.png" alt="" /></p><p>In this example there will be no actual rendering: it simply begins and ends a render pass, which results in clearing the buffers to a fixed value. The color buffer clear value changes on every frame.</p>
<a name="startup"></a>
<h4 id="startup">Startup</h4>
<p>Each Qt application using Vulkan will have to have a <code>Vulkan instance</code> which encapsulates application-level state and initializes a Vulkan library.</p>
<p>A <a href="qvulkanwindow.html">QVulkanWindow</a> must always be associated with a <a href="qvulkaninstance.html">QVulkanInstance</a> and hence the example performs instance creation before the window. The <a href="qvulkaninstance.html">QVulkanInstance</a> object must also outlive the window.</p>
<pre class="cpp">

      <span class="type"><a href="qvulkaninstance.html">QVulkanInstance</a></span> inst;

  <span class="preprocessor">#ifndef Q_OS_ANDROID</span>
      inst<span class="operator">.</span>setLayers(<span class="type"><a href="../qtcore/qbytearraylist.html">QByteArrayList</a></span>() <span class="operator">&lt;</span><span class="operator">&lt;</span> <span class="string">&quot;VK_LAYER_LUNARG_standard_validation&quot;</span>);
  <span class="preprocessor">#else</span>
      inst<span class="operator">.</span>setLayers(<span class="type"><a href="../qtcore/qbytearraylist.html">QByteArrayList</a></span>()
                     <span class="operator">&lt;</span><span class="operator">&lt;</span> <span class="string">&quot;VK_LAYER_GOOGLE_threading&quot;</span>
                     <span class="operator">&lt;</span><span class="operator">&lt;</span> <span class="string">&quot;VK_LAYER_LUNARG_parameter_validation&quot;</span>
                     <span class="operator">&lt;</span><span class="operator">&lt;</span> <span class="string">&quot;VK_LAYER_LUNARG_object_tracker&quot;</span>
                     <span class="operator">&lt;</span><span class="operator">&lt;</span> <span class="string">&quot;VK_LAYER_LUNARG_core_validation&quot;</span>
                     <span class="operator">&lt;</span><span class="operator">&lt;</span> <span class="string">&quot;VK_LAYER_LUNARG_image&quot;</span>
                     <span class="operator">&lt;</span><span class="operator">&lt;</span> <span class="string">&quot;VK_LAYER_LUNARG_swapchain&quot;</span>
                     <span class="operator">&lt;</span><span class="operator">&lt;</span> <span class="string">&quot;VK_LAYER_GOOGLE_unique_objects&quot;</span>);
  <span class="preprocessor">#endif</span>

      <span class="keyword">if</span> (<span class="operator">!</span>inst<span class="operator">.</span>create())
          <a href="../qtcore/qtglobal.html#qFatal">qFatal</a>(<span class="string">&quot;Failed to create Vulkan instance: %d&quot;</span><span class="operator">,</span> inst<span class="operator">.</span>errorCode());

</pre>
<p>The example enables validation layers, when supported. When the requested layers are not present, the request will be ignored. Additional layers and extensions can be enabled in a similar manner.</p>
<pre class="cpp">

      VulkanWindow w;
      w<span class="operator">.</span>setVulkanInstance(<span class="operator">&amp;</span>inst);

      w<span class="operator">.</span>resize(<span class="number">1024</span><span class="operator">,</span> <span class="number">768</span>);
      w<span class="operator">.</span>show();

</pre>
<p>Once the instance is ready, it is time to create a window. Note that <code>w</code> lives on the stack and is declared after <code>inst</code>.</p>
<a name="the-qvulkanwindow-subclass"></a>
<h4 id="the-qvulkanwindow-subclass">The QVulkanWindow Subclass</h4>
<p>To add custom functionality to a <a href="qvulkanwindow.html">QVulkanWindow</a>, subclassing is used. This follows the existing patterns from <a href="qopenglwindow.html">QOpenGLWindow</a> and <a href="../qtwidgets/qopenglwidget.html">QOpenGLWidget</a>. However, <a href="qvulkanwindow.html">QVulkanWindow</a> utilizes a separate <a href="qvulkanwindowrenderer.html">QVulkanWindowRenderer</a> object. This resembles <a href="../qtquick/qquickframebufferobject.html">QQuickFramebufferObject</a>, and allows better separation of the functions that are supposed to be reimplemented.</p>
<pre class="cpp">

  <span class="keyword">class</span> VulkanRenderer : <span class="keyword">public</span> <span class="type"><a href="qvulkanwindowrenderer.html">QVulkanWindowRenderer</a></span>
  {
  <span class="keyword">public</span>:
      VulkanRenderer(<span class="type"><a href="qvulkanwindow.html">QVulkanWindow</a></span> <span class="operator">*</span>w);

      <span class="type">void</span> initResources() override;
      <span class="type">void</span> initSwapChainResources() override;
      <span class="type">void</span> releaseSwapChainResources() override;
      <span class="type">void</span> releaseResources() override;

      <span class="type">void</span> startNextFrame() override;

  <span class="keyword">private</span>:
      <span class="type"><a href="qvulkanwindow.html">QVulkanWindow</a></span> <span class="operator">*</span>m_window;
      <span class="type"><a href="qvulkandevicefunctions.html">QVulkanDeviceFunctions</a></span> <span class="operator">*</span>m_devFuncs;
      <span class="type">float</span> m_green <span class="operator">=</span> <span class="number">0</span>;
  };

  <span class="keyword">class</span> VulkanWindow : <span class="keyword">public</span> <span class="type"><a href="qvulkanwindow.html">QVulkanWindow</a></span>
  {
  <span class="keyword">public</span>:
      <span class="type"><a href="qvulkanwindowrenderer.html">QVulkanWindowRenderer</a></span> <span class="operator">*</span>createRenderer() override;
  };

</pre>
<p>The <a href="qvulkanwindow.html">QVulkanWindow</a> subclass reimplements the factory function <a href="qvulkanwindow.html#createRenderer">QVulkanWindow::createRenderer</a>(). This simply returns a new instance of the <a href="qvulkanwindowrenderer.html">QVulkanWindowRenderer</a> subclass. In order to be able to access various Vulkan resources via the window object, a pointer to the window is passed and stored via the constructor.</p>
<pre class="cpp">

  <span class="type"><a href="qvulkanwindowrenderer.html">QVulkanWindowRenderer</a></span> <span class="operator">*</span>VulkanWindow<span class="operator">::</span>createRenderer()
  {
      <span class="keyword">return</span> <span class="keyword">new</span> VulkanRenderer(<span class="keyword">this</span>);
  }

  VulkanRenderer<span class="operator">::</span>VulkanRenderer(<span class="type"><a href="qvulkanwindow.html">QVulkanWindow</a></span> <span class="operator">*</span>w)
      : m_window(w)
  {
  }

</pre>
<p>Graphics resource creation and destruction is typically done in one of the init - resource functions.</p>
<pre class="cpp">

  <span class="type">void</span> VulkanRenderer<span class="operator">::</span>initResources()
  {
      <a href="../qtcore/qtglobal.html#qDebug">qDebug</a>(<span class="string">&quot;initResources&quot;</span>);

      m_devFuncs <span class="operator">=</span> m_window<span class="operator">-</span><span class="operator">&gt;</span>vulkanInstance()<span class="operator">-</span><span class="operator">&gt;</span>deviceFunctions(m_window<span class="operator">-</span><span class="operator">&gt;</span>device());
  }

</pre>
<a name="the-actual-rendering"></a>
<h4 id="the-actual-rendering">The Actual Rendering</h4>
<p><a href="qvulkanwindow.html">QVulkanWindow</a> subclasses queue their draw calls in their reimplementation of QVulkanWindowRenderer::startNextFrame(). Once done, they are required to call back <a href="qvulkanwindow.html#frameReady">QVulkanWindow::frameReady</a>(). The example has no asynchronous command generation, so the frameReady() call is made directly from startNextFrame().</p>
<pre class="cpp">

  <span class="type">void</span> VulkanRenderer<span class="operator">::</span>startNextFrame()
  {
      m_green <span class="operator">+</span><span class="operator">=</span> <span class="number">0.005f</span>;
      <span class="keyword">if</span> (m_green <span class="operator">&gt;</span> <span class="number">1.0f</span>)
          m_green <span class="operator">=</span> <span class="number">0.0f</span>;

      VkClearColorValue clearColor <span class="operator">=</span> {{ <span class="number">0.0f</span><span class="operator">,</span> m_green<span class="operator">,</span> <span class="number">0.0f</span><span class="operator">,</span> <span class="number">1.0f</span> }};
      VkClearDepthStencilValue clearDS <span class="operator">=</span> { <span class="number">1.0f</span><span class="operator">,</span> <span class="number">0</span> };
      VkClearValue clearValues<span class="operator">[</span><span class="number">2</span><span class="operator">]</span>;
      memset(clearValues<span class="operator">,</span> <span class="number">0</span><span class="operator">,</span> <span class="keyword">sizeof</span>(clearValues));
      clearValues<span class="operator">[</span><span class="number">0</span><span class="operator">]</span><span class="operator">.</span>color <span class="operator">=</span> clearColor;
      clearValues<span class="operator">[</span><span class="number">1</span><span class="operator">]</span><span class="operator">.</span>depthStencil <span class="operator">=</span> clearDS;

      VkRenderPassBeginInfo rpBeginInfo;
      memset(<span class="operator">&amp;</span>rpBeginInfo<span class="operator">,</span> <span class="number">0</span><span class="operator">,</span> <span class="keyword">sizeof</span>(rpBeginInfo));
      rpBeginInfo<span class="operator">.</span>sType <span class="operator">=</span> VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
      rpBeginInfo<span class="operator">.</span>renderPass <span class="operator">=</span> m_window<span class="operator">-</span><span class="operator">&gt;</span>defaultRenderPass();
      rpBeginInfo<span class="operator">.</span>framebuffer <span class="operator">=</span> m_window<span class="operator">-</span><span class="operator">&gt;</span>currentFramebuffer();
      <span class="keyword">const</span> <span class="type"><a href="../qtcore/qsize.html">QSize</a></span> sz <span class="operator">=</span> m_window<span class="operator">-</span><span class="operator">&gt;</span>swapChainImageSize();
      rpBeginInfo<span class="operator">.</span>renderArea<span class="operator">.</span>extent<span class="operator">.</span>width <span class="operator">=</span> sz<span class="operator">.</span>width();
      rpBeginInfo<span class="operator">.</span>renderArea<span class="operator">.</span>extent<span class="operator">.</span>height <span class="operator">=</span> sz<span class="operator">.</span>height();
      rpBeginInfo<span class="operator">.</span>clearValueCount <span class="operator">=</span> <span class="number">2</span>;
      rpBeginInfo<span class="operator">.</span>pClearValues <span class="operator">=</span> clearValues;
      VkCommandBuffer cmdBuf <span class="operator">=</span> m_window<span class="operator">-</span><span class="operator">&gt;</span>currentCommandBuffer();
      m_devFuncs<span class="operator">-</span><span class="operator">&gt;</span>vkCmdBeginRenderPass(cmdBuf<span class="operator">,</span> <span class="operator">&amp;</span>rpBeginInfo<span class="operator">,</span> VK_SUBPASS_CONTENTS_INLINE);

      <span class="comment">// Do nothing else. We will just clear to green, changing the component on</span>
      <span class="comment">// every invocation. This also helps verifying the rate to which the thread</span>
      <span class="comment">// is throttled to. (The elapsed time between startNextFrame calls should</span>
      <span class="comment">// typically be around 16 ms. Note that rendering is 2 frames ahead of what</span>
      <span class="comment">// is displayed.)</span>

      m_devFuncs<span class="operator">-</span><span class="operator">&gt;</span>vkCmdEndRenderPass(cmdBuf);

      m_window<span class="operator">-</span><span class="operator">&gt;</span>frameReady();
      m_window<span class="operator">-</span><span class="operator">&gt;</span>requestUpdate(); <span class="comment">// render continuously, throttled by the presentation rate</span>
  }

</pre>
<p>To get continuous updates, the example simply invokes <a href="qwindow.html#requestUpdate">QWindow::requestUpdate</a>() in order to schedule a repaint.</p>
<a name="running-the-example"></a>
<h4 id="running-the-example">Running the Example</h4>
<p>To run the example from <a href="http://doc.qt.io/qtcreator/index.html">Qt Creator</a>, open the <b>Welcome</b> mode and select the example from <b>Examples</b>. For more information, visit <a href="http://doc.qt.io/qtcreator/creator-build-example-application.html">Building and Running an Example</a>.</p>
<p><a href="https://code.qt.io/cgit/qt/qtbase.git/tree/examples/vulkan/hellovulkanwindow?h=5.14">Example project @ code.qt.io</a></p>
</div>
<!-- @@@hellovulkanwindow -->
        </div>
       </div>
   </div>
   </div>
</div>
<div class="footer">
   <p>
   <acronym title="Copyright">&copy;</acronym> 2020 The Qt Company Ltd.
   Documentation contributions included herein are the copyrights of
   their respective owners.<br/>    The documentation provided herein is licensed under the terms of the    <a href="http://www.gnu.org/licenses/fdl.html">GNU Free Documentation    License version 1.3</a> as published by the Free Software Foundation.<br/>    Qt and respective logos are trademarks of The Qt Company Ltd.     in Finland and/or other countries worldwide. All other trademarks are property
   of their respective owners. </p>
</div>
</body>
</html>
